/*
 * @Author: ls
 * @Date: 2021-11-19 16:47:44
 * @LastEditTime: 2021-11-22 13:42:53
 * @LastEditors: ls
 * @Description: 贝塞尔
 * @FilePath: \BezierCurvePathCreater-master\assets\scripts\Bezier.js
 */

/**
 * 创建贝塞尔
 * @param {*} pointArr 关键点集合
 * @param {*} allTime 总时间
 * @returns
 */
const Bezier = function (pointArr, allTime = 2) {
	let _this = {};

	/**曲线点集合 */
	let _pointLists;
	/**曲线总长 */
	let totalLength;
	/**上一个点 */
	let prevPos;
	/**当前时间 */
	let currentRunTime;

	/**运行时间 */
	let _runTime = allTime;
	/**关键点集合 */
	let _pointArr = pointArr;

	// ------------------------【Tools】---------------------------
	/**
	 * 阶乘
	 * @param {*} i
	 * @returns
	 */
	let factorial = function (i) {
		let n = 1;
		for (let j = 1; j <= i; j++) n *= j;
		return n;
	};

	// ------------------------【核心代码】---------------------------
	/**
	 * 重置数据
	 */
	let resetData = function () {
		// 清空曲线点集合
		_pointLists = [];
		// 清空曲线总长
		totalLength = 0;
		// 清空当前时间
		currentRunTime = 0;
		// 初始位置
		prevPos = {
			x: _pointArr[0].x,
			y: _pointArr[0].y,
			length: 0,
		};
	};

	/**
	 * 计算贝塞尔
	 * @param {*} dt
	 * @param {*} runTime
	 */
	let computeBezier = function (dt, runTime) {
		// 把时间从 [0,runTime] 映射到 [0,1] 之间
		let t = currentRunTime / runTime;

		let x = 0,
			y = 0;
		// 控制点数组
		let n = _pointArr.length - 1;

		_pointArr.forEach((item, index) => {
			if (index) {
				x += (factorial(n) / factorial(index) / factorial(n - index)) * item.x * Math.pow(1 - t, n - index) * Math.pow(t, index);
				y += (factorial(n) / factorial(index) / factorial(n - index)) * item.y * Math.pow(1 - t, n - index) * Math.pow(t, index);
			} else {
				x += item.x * Math.pow(1 - t, n - index) * Math.pow(t, index);
				y += item.y * Math.pow(1 - t, n - index) * Math.pow(t, index);
			}
		});

		// 二阶贝塞尔曲线公式 (t => [0,1])
		//  let x = Math.pow(1 - t, 2) * _startPos.x
		//  + 2 * t * (1 - t) * _controlPos.x
		//  + Math.pow(t, 2) * _endPos.x;

		//  let y = Math.pow(1 - t, 2) * _startPos.y
		//  + 2 * t * (1 - t) * _controlPos.y
		//  + Math.pow(t, 2) * _endPos.y;

		// console.log(`x:${x},y:${y}`);
		// 计算两点距离
		let length = Math.sqrt(Math.pow(prevPos.x - x, 2) + Math.pow(prevPos.y - y, 2));
		let v2 = { x, y, length };
		// 存储当前节点
		_pointLists.push(v2);
		prevPos = v2;
		// 累计长度
		totalLength += length;
		// 累计时间
		currentRunTime += dt;
	};

	/**
	 * 切割贝塞尔曲线
	 * @param {*} count
	 * @returns
	 */
	_this.getPoints = function (count = 200) {
		resetData();

		let dt = _runTime / count; // 分割时间
		for (let i = 0, len = count + 1; i < len; i++) {
			computeBezier(dt, _runTime); // 开始分割曲线
		}
		return _pointLists;
	};

	/**
	 * 获取曲线总长度
	 * @returns
	 */
	_this.getCurveLength = function () {
		return totalLength;
	};

	return _this;
};

module.exports = Bezier;
